﻿using ChessServer.Net;
using ChessServer.Log;
using ChessServer.Common;
using System;

namespace ChessServer {
    public class NetHelper {

        private static NetHelper _instance;

        public static NetHelper instance {
            get {
                if ( _instance == null ) {
                    _instance = new NetHelper ();
                }
                return _instance;
            }
        }

        public int Init () {
            TcpSocketServer.instance.Connected += OnConnect;
            TcpSocketServer.instance.Handshaked += OnHandshaked;
            TcpSocketServer.instance.Disconnected += OnDisconnected;
            TcpSocketServer.instance.OnClosedStatus += OnClosedStatus;
            TcpSocketServer.instance.DataReceived += OnDataReceived;
            return TcpSocketServer.instance.Init ();
        }

        public int Run () {
            TcpSocketServer.instance.StartListen ();
            return 0;
        }

        private void OnConnect ( TcpSocketServer netins, ConnectionEventArgs e ) {
            try {
                var session = GameSession.CreateNew ( e.Socket, netins );
                session.HeartbeatTimeoutHandle += OnHeartbeatTimeout;
                OnConnectCompleted ( netins, e );
            }
            catch ( Exception err ) {
                OurDebug.LogErrorFormat ( "ConnectCompleted error:{0}", err );
            }
        }

        private void OnConnectCompleted ( TcpSocketServer netins, ConnectionEventArgs e ) {
            OurDebug.LogFormat ( "someone connected sessionid:{0}", e.Socket.HashCode );
        }

        protected void OnHeartbeatTimeout ( GameSession session ) {
            // TODO 心跳超时,应该断开连接并且设置离线相关代码了
            session.Close ();
        }

        private void OnHandshaked ( TcpSocketServer netins, ConnectionEventArgs e ) {
        }

        private void OnDisconnected ( TcpSocketServer netins, ConnectionEventArgs e ) {
            try {
                GameSession session = GameSession.Get ( e.Socket.HashCode );
                if ( session != null ) {
                    OnDisconnected ( session );
                    session.Close ();
                }
            }
            catch ( Exception err ) {
                OurDebug.LogErrorFormat ( "Disconnected error:{0}", err );
            }
        }

        private void OnDisconnected ( GameSession session ) {
            OurDebug.LogFormat ( "someone disconnected sessionid:{0}", session.SessionId );
        }

        private void OnClosedStatus ( ExSocket exsocket, int arg2 ) {
        }

        private void OnDataReceived ( TcpSocketServer netins, ConnectionEventArgs e ) {
            try {
                OnReceivedBefore ( e );
                var session = GetSession ( e );
                // 投递给对应的
                var msgbytes = e.Message.data;
                var msgid = e.Message.msgid;

                // 测试
                if ( msgid == ( int ) protol.MsgID.simple_rpc ) {
                    var msgstr = System.Text.Encoding.UTF8.GetString ( msgbytes );
                    OurDebug.LogFormat ( "OnDataReceived msgid:{0} msg:{1}", msgid, msgstr );
                }
            }
            catch ( Exception ex ) {
                OurDebug.LogErrorFormat ( "Received to Host:{0} error:{1}", e.Socket.RemoteEndPoint, ex );
            }
        }

        private void OnReceivedBefore ( ConnectionEventArgs e ) {
        }

        /// <summary>
        /// 根据发来的消息的头来查找在服务器上的连接
        /// 如果是断线后重连，则会根据消息头里的sessionid找到先前的连接
        /// !session.Connected这个代码会发现之前的连接已经断开，就会Recover
        /// Recover会把连接号直接设置成上次断开的hashcode，之前的socket断开。
        /// </summary>
        /// <param name="e"></param>
        /// <param name="package"></param>
        /// <returns></returns>
        private GameSession GetSession ( ConnectionEventArgs e ) {
            //
            GameSession session = GameSession.Get ( e.Socket.HashCode );

            if ( session == null ) {
                // TODO huhu 第一个参数不知道干啥用的
                session = GameSession.CreateNew ( e.Socket, TcpSocketServer.instance );
            }
            return session;
        }
    }
}